/**
 * 内容管理器CM(Content Manager)初始化
 * @param {Object} window
 * @param {Object} undefined
 */

var CM = window.CM || {}
CM.init = function(config) {

	(function(window, config) {

		var _CQ = {
			_CLOSE_IMG: '',
		}


		if(!config) {
			throw 'the config must be required'
		}

		var _CONST = {
			messageType: {
				TYPE_IMG: 'messageType/img',
				TYPE_TEXT: 'messageType/text',
				TYPE_VIDEO: 'messageType/video',
				TYPE_RADIO: 'messageType/radio'
			},
			taskType: {
				TASK_SEND: 'task/send',
				TASK_SR: 'task/sr',
				TASK_EVALUATE: 'task/evaluate',
				TASK_REDIRECT: 'task/redirect',
				TASK_CLOSE: 'task/close'
			},
			groupId: {
				GROUP_DEF_SINGLE: 'groupDefSingle',
				GROUP_DEF_CLIENT: 'groupDefClient',
				GROUP_DEF_STAFF: 'groupDefStaff'
			}
		}

		var _infoOutput = _defFalse(config.infoOutput)

		var CM = {
			infoOutput: _infoOutput,
			info: [],
			config: config,
			CONST: _CONST
		}
		window.CM = CM;

		/**
		 * 通用函数
		 */

		/**
		 * 默认返回true值
		 * @param {Object} val 如果val为undefined或者true的时候返回true，只有在为false的时候返回false
		 */
		function _defTrue(val) {
			if(val == undefined) {
				return true
			}
			return val
		}

		/**
		 * 默认返回false值
		 * @param {Object} val 如果val为undefined或者false的时候返回false，只有在为true的时候返回true
		 */
		function _defFalse(val) {
			if(val == undefined) {
				return false
			}
			return val
		}

		/**
		 * 根据HTML字符串设置在指定的位置【生成(如果该选择器对于的区域已经有html代码，则会直接覆盖)】标签
		 * @param {String} selectorStr 选择器字符串
		 * @param {String} htmlStr html标签字符串
		 */
		function _genHtmlTag(selectorStr, htmlStr) {
			var target = $(selectorStr)
			if(target.html().trim().length != 0) {
				_warn('the html tag has be delete')
			}
			$(selectorStr).html(htmlStr)
		}

		/**
		 * 根据HTML字符串设置在指定的位置【追加】标签
		 * @param {Object} selectorStr 选择器字符串
		 * @param {Object} htmlStr html标签字符串
		 */
		function _appendHtmlTag(selectorStr, htmlStr) {
			$(selectorStr).append(htmlStr)
		}

		function _stopPropagation(e) {
			if(e && e.stopPropagation) {
				//支持w3c的stopPropagation()方法
				e.stopPropagation();
			} else {
				//使用ie的方式取消冒泡
				window.event.cancelBubble = true;
			}
		}

		function _console(val) {
			if(_infoOutput) {
				if(window.console) {
					console.log(val)
				} else {
					CM.info.push(val)
				}
			}
		}

		function _isString(val) {
			return Object.prototype.toString.call(val) === '[object String]';
		}

		function _isBlank(val) {
			if(_isFunction(val)) {
				throw 'the params of function[isBlank] can\'t be a function'
			}
			if(!val) {
				return true;
			}
			if(_isArray(val) && val.length == 0) {
				return true;
			}
			return false
		}

		function _isArray(val) {
			if(!val) {
				return false;
			}
			return Object.prototype.toString.call(val) === '[object Array]';
		}

		function _isFunction(val) {
			if(!val) {
				return false;
			}
			return Object.prototype.toString.call(val) === '[object Function]';
		}

		function _inArray(val, arr) {
			for(var i = 0, len = arr.length; i < len; i++) {
				if(val === arr[i]) {
					return i;
				}
			}
			return -1;
		}

		function _each(obj, fn) {
			if(_isArray(obj)) {
				for(var i = 0, len = obj.length; i < len; i++) {
					if(fn.call(obj[i], i, obj[i]) === false) {
						break;
					}
				}
			} else {
				for(var key in obj) {
					if(obj.hasOwnProperty(key)) {
						if(fn.call(obj[key], key, obj[key]) === false) {
							break;
						}
					}
				}
			}
		}

		function _trim(str) {
			return str.replace(/(?:^[ \t\n\r]+)|(?:[ \t\n\r]+$)/g, '');
		}

		function _inString(val, str, delimiter) {
			delimiter = delimiter === undefined ? ',' : delimiter;
			return(delimiter + str + delimiter).indexOf(delimiter + val + delimiter) >= 0;
		}

		function _addUnit(val, unit) {
			unit = unit || 'px';
			return val && /^-?\d+(?:\.\d+)?$/.test(val) ? val + unit : val;
		}

		function _removeUnit(val) {
			var match;
			return val && (match = /(\d+)/.exec(val)) ? parseInt(match[1], 10) : 0;
		}

		function _escape(val) {
			return val.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
		}

		function _unescape(val) {
			return val.replace(/&lt;/g, '<').replace(/&gt;/g, '>').replace(/&quot;/g, '"').replace(/&amp;/g, '&');
		}

		function _toCamel(str) {
			var arr = str.split('-');
			str = '';
			_each(arr, function(key, val) {
				str += (key > 0) ? val.charAt(0).toUpperCase() + val.substr(1) : val;
			});
			return str;
		}

		function _toHex(val) {
			function hex(d) {
				var s = parseInt(d, 10).toString(16).toUpperCase();
				return s.length > 1 ? s : '0' + s;
			}
			return val.replace(/rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/ig,
				function($0, $1, $2, $3) {
					return '#' + hex($1) + hex($2) + hex($3);
				}
			);
		}

		function _toMap(val, delimiter) {
			delimiter = delimiter === undefined ? ',' : delimiter;
			var map = {},
				arr = _isArray(val) ? val : val.split(delimiter),
				match;
			_each(arr, function(key, val) {
				if((match = /^(\d+)\.\.(\d+)$/.exec(val))) {
					for(var i = parseInt(match[1], 10); i <= parseInt(match[2], 10); i++) {
						map[i.toString()] = true;
					}
				} else {
					map[val] = true;
				}
			});
			return map;
		}

		function _toArray(obj, offset) {
			return Array.prototype.slice.call(obj, offset || 0);
		}

		function _undef(val, defaultVal) {
			return val === undefined ? defaultVal : val;
		}

		function _invalidUrl(url) {
			return !url || /[<>"]/.test(url);
		}

		function _addParam(url, param) {
			return url.indexOf('?') >= 0 ? url + '&' + param : url + '?' + param;
		}

		function _extend(child, parent, proto) {
			if(!proto) {
				proto = parent;
				parent = null;
			}
			var childProto;
			if(parent) {
				var fn = function() {};
				fn.prototype = parent.prototype;
				childProto = new fn();
				_each(proto, function(key, val) {
					childProto[key] = val;
				});
			} else {
				childProto = proto;
			}
			childProto.constructor = child;
			child.prototype = childProto;
			child.parent = parent ? parent.prototype : null;
		}

		function _json(text) {
			var match;
			if((match = /\{[\s\S]*\}|\[[\s\S]*\]/.exec(text))) {
				text = match[0];
			}
			var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
			cx.lastIndex = 0;
			if(cx.test(text)) {
				text = text.replace(cx, function(a) {
					return '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
				});
			}
			if(/^[\],:{}\s]*$/.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@').replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
				return eval('(' + text + ')');
			}
			throw 'JSON parse error';
		}

		/**
		 * 初始化配置参数指定的参数
		 */
		var _tsConf
		if((_tsConf = config.tsConf)) {
			// 添加tempStorage
			(function(CM) {
				if(CM.ts) {
					return
				}

				var _STORAGE_TYPE_MEMORY = 'memoryStorage' //内存缓存类型，不支持页面刷新后重新渲染
				var _STORAGE_TYPE_LOCAL = 'localStorage' //浏览器缓存类型，支持页面刷新后页面重新渲染，但不支持缓存清空后的页面重新渲染
				var _STORAGE_TYPE_REMOTE = 'remoteStorage' //远程缓存类型，最高缓存级别，只有开启缓存并且localStorage不可用的情况下才能使用，就是说，在localStorage可用的情况下，即时开启了远程缓存，也不会在远程服务器上进行缓存
				var _storageType = _STORAGE_TYPE_LOCAL

				// 拷贝默认属性
				_tsConf = Object.assign({
					/**
					 * 默认为_STORAGE_TYPE_LOCAL
					 * 存储器类别，一般为localStorage，如果开启了页面记录缓存，而ocalStorage不可用，
					 * 并且开启了强制缓存的时候，则类别为remoteStorage
					 */
					useStorage: true,
					forceStore: false,
					uniquePrefix: "_CM_TP_",

				}, _tsConf)

				var _useStorage = _tsConf.useStorage
				var _forceStore = _tsConf.forceStore
				var _uniquePrefix = _tsConf.uniquePrefix // key前缀
				var _jsms = new Map // javascript memory storage

				if(_useStorage) {
					if(_storageAvailable(_storageType)) {
						_storageType = _STORAGE_TYPE_LOCAL
					} else if(_forceStore) {
						// localstorage不可用，但是开启了强制存储
						_storageType = _STORAGE_TYPE_REMOTE
					}
				} else {
					_storageType = _STORAGE_TYPE_MEMORY
				}

				_tsConf._storageType = _storageType
				_tsConf._isSupportReload = (_storageType != _STORAGE_TYPE_MEMORY)

				function _storageAvailable(type) {
					try {
						var storage = window[type],
							x = '__storage_test__';
						storage.setItem(x, x);
						storage.removeItem(x);
						return true;
					} catch(e) {
						return e instanceof DOMException &&
							(
								e.code === 22 ||
								e.code === 1014 ||
								e.name === 'QuotaExceededError' ||
								e.name === 'NS_ERROR_DOM_QUOTA_REACHED') &&
							storage.length !== 0;
					}
				}

				function _reload(records) {
					var record
					for(var i = 0, len = records.length; i < len; i++) {
						record = records[i]
						var id = record.receiverId
						var name = record.receiverName
						if(record.senderId != CM.tp.senderId) {
							// 如果是接收别人的信息，需要逆转id
							id = record.senderId
							name = record.senderName
						}
						CM.tp.genTabTag(id, name, CM.tp.autoChoose)
					}
				}
				//重新加载聊天框页面
				function _reloadRecords() {
					switch(_storageType) {
						case _STORAGE_TYPE_MEMORY:
							if(_jsms.size != 0) {
								var record
								_jsms.forEach(function(val, key) {
									_reload(val)
								})
							} else {
								_console('warning:it is not support reload after page refresh')
							}
							break;
						case _STORAGE_TYPE_LOCAL:
							for(var x in localStorage) {
								if(x.startsWith(_uniquePrefix)) {
									var records = JSON.parse(localStorage[x])
									_reload(records)
								}
							}
							break;
						case _STORAGE_TYPE_REMOTE:
							/*远程操作*/
							break;
						default:
							break;
					}
				}

				function _save(key, value) {
					if(!key || !value) {
						throw 'sava方法必须有两个参数key和value'
					}
					var values = _get(key) || []
					values.push(value)
					switch(_storageType) {
						case _STORAGE_TYPE_MEMORY:
							_jsms.set(_uniquePrefix + key, values);
							break;
						case _STORAGE_TYPE_LOCAL:
							localStorage.setItem(_uniquePrefix + key, JSON.stringify(values));
							break;
						case _STORAGE_TYPE_REMOTE:
							/*远程操作*/
							break;
						default:
							break;
					}
				}

				function _get(key) {
					key = _uniquePrefix + key
					switch(_storageType) {
						case _STORAGE_TYPE_MEMORY:
							return _jsms.get(key);
							break;
						case _STORAGE_TYPE_LOCAL:
							return JSON.parse(localStorage.getItem(key)) || [];
							break;
						case _STORAGE_TYPE_REMOTE:
							return [];
							break;
						default:
							break;
					}
				}

				function _del(key) {
					key = _uniquePrefix + key
					switch(_storageType) {
						case _STORAGE_TYPE_MEMORY:
							_jsms.delete(key);
							break;
						case _STORAGE_TYPE_LOCAL:
							return localStorage.removeItem(key);
							break;
						case _STORAGE_TYPE_REMOTE:
							break;
						default:
							break;
					}
				}

				var ts = {
					config: _tsConf,
					reloadRecords: _reloadRecords,
					_jsms: _jsms,
					// 追加一条记录
					save: _save,
					// 获取某人所有当前记录
					get: _get,
					// 删除某人的聊天记录			
					del: _del,
				}
				ts.config = _tsConf
				ts = Object.assign(ts, ts.config)
				CM.config.tsConf = _tsConf
				CM.ts = ts
			})(window.CM)
		}
		
		
		var _tpConf
		if((_tpConf = config.tpConf)) {
			// 添加talkpanel
			(function(CM) {
				if(CM.tp) {
					return
				}
				var _kConf = _tpConf.kConf || {}
				// 拷贝_kConf的默认属性
				_kConf = Object.assign({
					kContentName: 'cm-ke-content',
					filterMode: true,
					newlineTag: "br",
					htmlTags: {
						img: ['src', 'width', 'height', 'border', 'alt', 'title', 'align', '.width', '.height', '.border']
					},
					afterCreate: function() {
						var self = this
						var doc = this.edit.doc;
						var cmd = this.edit.cmd;
						$(doc.body).bind('paste', function(ev) {
							var $this = $(this);
							var dataItem = ev.originalEvent.clipboardData.items[0];
							if(dataItem) {
								var file = dataItem.getAsFile();
								if(file) {
									var reader = new FileReader();
									reader.onload = function(evt) {
										var image = new Image();
										var imageDataBase64 = evt.target.result
										image.src = imageDataBase64
										image.onload = function() {
											var widthAfterCalc
											if(image.width > 1000) {
												widthAfterCalc = image.width * 0.4 + "px"
											} else if(image.width > 500) {
												widthAfterCalc = image.width * 0.7 + "px"
											} else if(image.width > 200) {
												widthAfterCalc = image.width * 0.9 + "px"
											} else {
												widthAfterCalc = image.width + "px"
											}
											cmd.inserthtml("<img src='" + imageDataBase64 + "' style='width:" + widthAfterCalc + ";'>")
											/*											setTimeout(function() {
																							$this.viewer('update')
																						}, 100)*/
										};
									};
									reader.readAsDataURL(file);
								}
							}
						});
						//右键菜单绑定
						$(doc.body).bind('contextmenu', function(ev) {
							var t = $(ev.target)
							if(!t.hasClass('ke-content')) {
								// 如果右键点击在图片上
								return
							} else {

							}
						});
						// enter发送
						var txt = $("iframe").contents().find("body");
						txt.keydown(function(event) {
							if(event.keyCode == 13 && !event.ctrlKey) {
								self.sync();
								return false
							}
						})
					}
				}, _kConf)

				// 拷贝默认属性
				_tpConf = Object.assign({
					senderId: '',
					senderName: '匿名用户',
					autoChoose: true,
					autoReload: true,
					beforeTabClose: '_defBeforeTabClose',
					afterTabClose: '_defAfterTabClose',
					beforeTabChoosed: '_defBeforeTabChoosed',
					afterTabChoosed: '_defAfterTabChoosed',
					recordsRenderer: '_defRecordsRenderer',
					maxUnread:	99,
					closeTag: 'b',
					closeImgSrc: _CQ._CLOSE_IMG
				}, _tpConf)
				_tpConf.kConf = _kConf

				var _USER_TAB_CHOOSED_CLASS = 'cm-tab-choosed'
				var _CM_TAB_LIST_CLASS = 'cm-tab-list'
				var _USER_TAB_CLASS = 'cm-tab'
				var _USERNAME_CLASS = 'cm-tab-username'
				var _UNREAD_CLASS = 'cm-tab-unread'
				var _TAB_CLOSE_CLASS = 'cm-tab-close'

				var _CM_CONTENT_CLASS = 'cm-content'
				var _CM_CONTENT_SHOW_CLASS = 'cm-content-show'
				var _CM_CONTENT_INPUT_CLASS = 'cm-content-input'

				var _autoChoose = _tpConf.autoChoose
				var _autoReload = _tpConf.autoReload
				var _beforeTabClose = _tpConf.beforeTabClose
				var _afterTabClose = _tpConf.afterTabClose
				var _beforeTabChoosed = _tpConf.beforeTabChoosed
				var _afterTabChoosed = _tpConf.afterTabChoosed
				var _recordsRenderer = _tpConf.recordsRenderer
				var _kContentName = _tpConf.kConf.kContentName
				var _maxUnread = _tpConf.maxUnread
				var _closeTag = _tpConf.closeTag
				var _closeImgSrc = _tpConf.closeImgSrc
				
				function _tabClose(tab) {
					if(!tab) {
						return
					}
					tab = $(tab).parent('.' + _USER_TAB_CLASS)
					eval('(' + _beforeTabClose + '($(tab)))')
					$(tab).remove()
					if(tab.hasClass(_USER_TAB_CHOOSED_CLASS) && _autoChoose) {
						var tabs = $('.' + _USER_TAB_CLASS)
						if(tabs.length == 0) {
							_console('all tab has been closed')
							// 清空cmContent，或者显示主页
							tp.cmContent.html('')
						} else {
							_tabChoosed($(tabs[0]))
						}
					}
					eval('(' + _afterTabClose + '($(tab)))')
					var event = window.event || event
					if(event) {
						_stopPropagation(event)
					}
				}
				
				function _tabChoosed(tabNew) {
					tabNew = $(tabNew)
					tp.tabNew = tabNew
					tp.tabOld = $('.' + _USER_TAB_CHOOSED_CLASS)
					var records = CM.ts.get(tabNew.find('.' + _USERNAME_CLASS).attr('data-receiverid')) || []
					eval('(' + _beforeTabChoosed + '(tabNew, records))')
					if(tp.tabOld.length != 0) {
						tp.tabOld.removeClass(_USER_TAB_CHOOSED_CLASS)
					}
					tp.tabNew.addClass(_USER_TAB_CHOOSED_CLASS)
					// 清空未读数
					tabNew.find('.' + _UNREAD_CLASS).text('')
					eval('(' + _afterTabChoosed + '(tabNew, records))')
					// 渲染器执行
					var htmlStr = ''
					var record
					for(var i = 0, len = records.length; i < len; i++) {
						record = records[i]
						if(record.senderId == CM.tp.senderId) {
							// 如果是自己发送的信息，给record增加一个字段isSelf表示是自己发出去的信息
							record.isSelf = true
						} else {
							record.isSelf = false
						}
						htmlStr += eval('(' + _recordsRenderer + '(record, i))')
					}
					tp.cmContent.html(htmlStr)

					var event = window.event || event
					if(event) {
						_stopPropagation(event)
					}
				}

				function _defBeforeTabClose(tab) {
					_console('do something before tab[' + tab.text() + '] close...')
				}

				function _defAfterTabClose(tab) {
					_console('do something after tab[' + tab.text() + '] close...')
				}

				function _defBeforeTabChoosed(tabNew) {
					_console('do something before tab[' + tabNew.text() + '] choosed...')
				}

				function _defAfterTabChoosed(tabNew) {
					_console('do something after tab[' + tabNew.text() + '] choosed...')
				}

				function _defRecordsRenderer(record, i) {
					//默认渲染器
					return '<p>' + JSON.stringify(record) + '</p>'
				}
				
				/**
				 * 根据msgObj生成记录
				 * @param {Object} msgObj
				 */
				function _genRecord(record) {
					if(record.senderId == CM.tp.senderId) {
						record.isSelf = true
					} else {
						record.isSelf = false
					}
					var htmlStr = tp.cmContent.html()
					htmlStr += eval('(' + _recordsRenderer + '(record, 0))')
					tp.cmContent.html(htmlStr)
				}
				
				/**
				 * 
				 * @param {Object} msg	要发送的信息
				 * @param {String} receiverId 接收信息指定的人的唯一标识或者指定的组的唯一标识
				 * @param {String} receiverName
				 * @param {String} p_message_type 默认为text类型
				 * @param {String} p_task_type 默认为send类型
				 */
				function _createMsg(p_msg, p_receiverId, p_receiverName, p_message_type, p_task_type) {
					return {
						senderId: CM.tp.senderId,
						senderName: CM.tp.senderName,
						receiverId: p_receiverId || null,
						receiverName: p_receiverName || null,
						msg: p_msg,
						timestamp: new Date().getTime(),
						taskType: p_task_type || CM.CONST.taskType.TASK_SEND_1,
						messageType: p_message_type || CM.CONST.messageType.TEXT
					}
				}

				function _initPanel() {
					var cmPanel = $(_tpConf.panelSelector)
					if(cmPanel.length == 0) {
						throw 'there is no selector for \'' + container + '\''
					}
					// 插入cm-tab-list
					cmPanel.append('<div class=\'' + _CM_TAB_LIST_CLASS + '\'></div>')
					// 插入cm-content
					cmPanel.append('<div class=\'' + _CM_CONTENT_CLASS + '\'>' +
						'<div class=\'' + _CM_CONTENT_SHOW_CLASS + '\'></div></div>')
					tp.cmContent = $('.' + _CM_CONTENT_SHOW_CLASS)
					// 如果要在页面渲染后就可以加载页面
					if(CM.ts._isSupportReload && _autoReload) {
						CM.ts.reloadRecords()
					}
				}

				/**
				 * 创建联系人tab
				 * @param {String} receiverId 信息接收者的唯一id,可以为组id
				 * @param {String} receiverName 联系人的名称，该名称用于页面显示，当receiverId为组id时，receiverName为组的名称
				 * @param {Boolean} choosed 创建的tab是加上选中样式
				 */
				function _createLinkerTabStr(receiverId, receiverName) {
					var htmlStr = "<div onclick=\"CM.tp.tabChoosed(this)\"" + " class=\'" + _USER_TAB_CLASS
					/*				if(choosed) {
										// 移除其他_USER_TAB_CHOOSED_CLASS
										$('.' + _USER_TAB_CHOOSED_CLASS).removeClass(_USER_TAB_CHOOSED_CLASS)
										htmlStr += ' ' + _USER_TAB_CHOOSED_CLASS
									}*/
					htmlStr += '\'>'
					htmlStr += '<div class=\'' + _USERNAME_CLASS + '\' data-receiverId=\'' + receiverId +
						'\' data-receiverName=\'' + receiverName + '\'>' + receiverName + '</div>' +
						'<b class=\'' + _UNREAD_CLASS + '\' style=\'\'></b>'
						
					if(_closeTag != 'b' && _closeTag != 'i') {
						if(_closeTag == 'img' && _closeImgSrc) {
							htmlStr += '<'+_closeTag + ' src=\''+ _closeImgSrc+'\' class=\'' + _TAB_CLOSE_CLASS + '\' onclick=\'CM.tp.tabClose(this)\'></' + _closeTag+'>'
							return htmlStr
						} else {
							_closeTag = 'b'
						}
					} else {
						_closeTag = 'b'
					}
					htmlStr += '<'+_closeTag + ' class=\'' + _TAB_CLOSE_CLASS + '\' onclick=\'CM.tp.tabClose(this)\'>×</' + _closeTag+'>'
					return htmlStr
				}

				function _incre(val) {
					if(!val) {
						return '1'
					}
					try {
						val = parseInt(val)
						if(val == _maxUnread) {
							return _maxUnread + '+'
						} else {
							return ++val
						}
					} catch(e) {
						return _maxUnread + '+'
					}
				}
		
				/**
				 * 生成tab并设置与其对应的内容
				 * @param {String} receiverId 接受者的id，即选中该tab后，所有的信息都是发给该id对应的人或者组
				 * @param {String} receiverName 接受者的名称，用于页面上的显示
				 * @param {Boolean} isChoosed 创建后是否被选中，可选参数，不传该参数就是默认是选中
				 */
				function _genTabTag(receiverId, receiverName, isChoosed) {
					var tempTab = $('.' + _USERNAME_CLASS + '[data-receiverid=' + receiverId + ']')
					// 如果已经创建了tab，就不用继续创建了
					if(tempTab.length != 0) {
						return
					}
					isChoosed = _defTrue(isChoosed)
					var tab = $(_createLinkerTabStr(receiverId, receiverName, isChoosed))
					$('.' + _CM_TAB_LIST_CLASS).append(tab)
					if(isChoosed) {
						_tabChoosed(tab)
					} 
				}
				
				function _setSenderId(senderId) {
					CM.tp.senderId = senderId
				}
				function _setSenderName(senderName) {
					CM.tp.senderName = senderName
				}
				var tp = {
					config: _tpConf,
					createMsg: _createMsg,
					tabClose: _tabClose,
					tabChoosed: _tabChoosed,
					genTabTag: _genTabTag,
					cmContent: null,
					tabNew: null,
					tabOld: null,
					autoReload: _autoReload,
					genRecord: _genRecord,
					setSenderId: _setSenderId,
					setSenderName: _setSenderName
				}
				tp.config = _tpConf
				tp = Object.assign(tp, tp.config)
				CM.config.tpConf = _tpConf
				CM.tp = tp
				_initPanel()
			})(CM)
		}

		// webSocket配置

	})(window, config)

}